package pe.gob.bcrp.sgci.gestion.reportes.model.dao.impl;


import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.*;

import javax.persistence.*;

import pe.gob.bcrp.sgci.gestion.reportes.model.dao.DAO;

public abstract class DAOImpl<T extends Serializable> implements DAO<T> {

    protected EntityManagerFactory factory = 
    		Persistence.createEntityManagerFactory("dssgcipool");
    
    protected EntityManager em;
    protected Class<T> persistenceClass;
    protected Map<String, String> properties;

    public DAOImpl() {
    	properties = new HashMap<String, String>();
		properties.put("eclipselink.jdbc.exclusive-connection.mode", "Always");
		properties.put("eclipselink.jdbc.exclusive-connection.is-lazy", "false");
		this.persistenceClass = (Class<T>) ((ParameterizedType) getClass().
                getGenericSuperclass()).getActualTypeArguments()[0];
    }

    public void add(T object) {
    	em = factory.createEntityManager(properties);
        em.persist(object);
        em.close();
    }

    public void update(T object) {
    	em = factory.createEntityManager(properties);
        em.merge(object);
        em.close();
    }

    public void delete(Object id) {
    	em = factory.createEntityManager(properties);
        T o = em.find(persistenceClass, id);
        em.close();
        delete(o);
    }

    public void delete(T object) {
    	em = factory.createEntityManager(properties);
        if (object != null) {
            em.remove(object);
        }
        em.close();
    }

    public T findById(Object id) {
    	em = factory.createEntityManager(properties);
    	T tmp = em.find(persistenceClass, id);
    	em.close();
        return tmp;
    }

    public List<T> findAll() {
    	List<T> tmp;
        String query = "SELECT o FROM " + persistenceClass.getSimpleName() +" o ";
        em = factory.createEntityManager(properties);
        tmp = em.createQuery(query, persistenceClass).getResultList();
        em.close();
        return tmp;
    }

    public void refresh(List<T> result) {
    	for (T o : result) {
    		em = factory.createEntityManager(properties);
            em.refresh(o);
            em.close();
        }
    }

    public void refresh(T o) {
    	em = factory.createEntityManager(properties);
        em.refresh(o);
        em.close();
    }

    public List<T> findByColumnName(String columnName, Object value) {
    	List<T> tmp;
        String query = "SELECT o FROM " + persistenceClass.getSimpleName() + " o WHERE o." + columnName + " = :" + columnName;
        em = factory.createEntityManager(properties);
        tmp = em.createQuery(query, persistenceClass).setParameter(columnName, value).getResultList();
        em.close();
        return tmp;
    }

    public List<T> findLikeColumnName(String columnName, String value) {
    	List<T> tmp;
        String query = "SELECT o FROM " + persistenceClass.getSimpleName() + " o WHERE o." + columnName + " LIKE :" + columnName;
        StringBuffer sb = new StringBuffer();
        sb.append("%");
        sb.append(value);
        sb.append("%");
        em = factory.createEntityManager(properties);
        tmp = em.createQuery(query, persistenceClass).setParameter(columnName, sb.toString()).getResultList();
        em.close();
        return tmp;
    }

    public List<T> namedQuery(String queryName, List<Object> parameterValues) {
    	List<T> tmp;
    	em = factory.createEntityManager(properties);
        Query query = em.createNamedQuery(queryName, persistenceClass);
        tmp = setParameters(query, parameterValues).getResultList();
        em.close();
        return tmp;
    }

    public List<T> namedQuery(String queryName, Map<String, Object> parameterValues) {
    	List<T> tmp;
    	em = factory.createEntityManager(properties);
        Query query = em.createNamedQuery(queryName, persistenceClass);
        tmp = setParameters(query, parameterValues).getResultList();
        em.close();
        return tmp;
    }

    public List<T> query(String queryString, List<Object> parameterValues) {
    	List<T> tmp;
    	em = factory.createEntityManager(properties);
        Query query = em.createQuery(queryString, persistenceClass);
        tmp = setParameters(query, parameterValues).getResultList();
        em.close();
        return tmp;
    }

    public List<T> query(String queryString, Map<String, Object> parameterValues) {
    	List<T> tmp;
    	em = factory.createEntityManager(properties);
        Query query = em.createQuery(queryString, persistenceClass);
        tmp = setParameters(query, parameterValues).getResultList();
        em.close();
        return tmp;
    }

    public List<T> nativeQuery(String queryString, List<Object> parameterValues) {
    	List<T> tmp;
    	em = factory.createEntityManager(properties);
        Query query = em.createNativeQuery(queryString, persistenceClass);
        tmp = setParameters(query, parameterValues).getResultList();
        em.close();
        return tmp;
    }

    public List<T> nativeQuery(String queryString, Map<String, Object> parameterValues) {
    	List<T> tmp;
    	em = factory.createEntityManager(properties);
        Query query = em.createNativeQuery(queryString, persistenceClass);
        tmp = setParameters(query, parameterValues).getResultList();
        em.close();
        return tmp;
    }

    public List<T> nativeQuery(String queryString, List<Object> parameterValues, String resultSetMapping) {
    	List<T> tmp;
    	em = factory.createEntityManager(properties);
        Query query = em.createNativeQuery(queryString, resultSetMapping);
        tmp = setParameters(query, parameterValues).getResultList();
        em.close();
        return tmp;
    }

    public List<T> nativeQuery(String queryString, Map<String, Object> parameterValues, String resultSetMapping) {
    	List<T> tmp;
    	em = factory.createEntityManager(properties);
        Query query = em.createNativeQuery(queryString, resultSetMapping);
        tmp = setParameters(query, parameterValues).getResultList();
        em.close();
        return tmp;
    }

    protected Query setParameters(Query query, List<Object> parameterValues) {
        int idx = 0;
        for (Object o : parameterValues) {
            query = query.setParameter(idx, o);
            idx++;
        }
        return query;
    }

    protected Query setParameters(Query query, Map<String, Object> parameterValues) {
        for (String key : parameterValues.keySet()) {
            query = query.setParameter(key, parameterValues.get(key));
        }
        return query;
    }
}
